package org.lanyu.springainovel.chat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.lanyu.springainovel.common.config.AIModelInitService;
import org.lanyu.springainovel.chat.entity.KnowledgeBase;
import org.lanyu.springainovel.common.config.VectorStoreManager;
import org.lanyu.springainovel.common.entity.User;
import org.lanyu.springainovel.chat.service.KnowledgeBaseService;
import org.lanyu.springainovel.common.service.UserService;
import org.lanyu.springainovel.common.util.DocumentSplitSaveUtil;
import org.lanyu.springainovel.chat.entity.KnowledgeDocument;
import org.lanyu.springainovel.chat.mapper.DocumentMapper;
import org.lanyu.springainovel.chat.service.KnowledgeDocumentService;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.filter.Filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 文档服务实现�?
 **/
@Service
public class KnowledgeDocumentServiceImpl implements KnowledgeDocumentService {

    @Autowired
    private DocumentMapper documentMapper;

    @Autowired
    private AIModelInitService aiModelInitService;
    
    @Value("${ai.file.upload-dir}")
    private String uploadDir;

    @Autowired
    private KnowledgeBaseService knowledgeBaseService;
    
    @Autowired
    private UserService userService;
    @Autowired
    private VectorStoreManager vectorStoreManager;

    @Override
    public KnowledgeDocument saveDocument(KnowledgeDocument document) {
        // 设置创建和更新时�?
        LocalDateTime now = LocalDateTime.now();
        document.setCreateTime(now);
        document.setUpdateTime(now);

        // 保存文档到数据库
        documentMapper.insert(document);

        // 如果关联了知识库，则保存文档到向量数据库
        if (document.getKnowledgeBaseId() != null) {
            saveDocumentToVectorStore(document);
        }

        return document;
    }

    /**
     * 将文档保存到向量数据�?     *
     * @param document 文档对象
     */
    private void saveDocumentToVectorStore(KnowledgeDocument document) {
        try {
            // 检查向量存储是否启用
            if (!vectorStoreManager.isVectorStoreEnabled()) {
                System.out.println("向量存储功能已禁用，跳过文档向量存储操作");
                return;
            }
            
            // 获取关联的知识库
            KnowledgeBase knowledgeBase = knowledgeBaseService.getKnowledgeBase(document.getKnowledgeBaseId());
            if (knowledgeBase == null) {
                System.err.println("无法保存文档到向量数据库：找不到关联的知识库，ID: " + document.getKnowledgeBaseId());
                return;
            }

            // 获取向量索引名称
            String indexName = knowledgeBase.getVectorIndexName();
            if (indexName == null || indexName.isEmpty()) {
                // 如果知识库没有设置向量索引名称，则使用默认命名规�?
                indexName = "kb_" + knowledgeBase.getId();
                // 更新知识库的向量索引名称
                knowledgeBase.setVectorIndexName(indexName);
                knowledgeBaseService.updateKnowledgeBase(knowledgeBase);
            }
            
            // 获取文档创建者的用户信息
            User user = null;
            if (document.getCreatedBy() != null) {
                user = userService.getUserById(document.getCreatedBy());
            }
            
            // 根据用户获取对应的向量存�?
            VectorStore vectorStore = aiModelInitService.getVectorStoreByUser(user, indexName);
            if (vectorStore == null) {
                System.err.println("无法保存文档到向量数据库：向量存储未初始化");
                return;
            }

            // 元数据信�?
            Map<String, Object> metadata = new HashMap<>();
            metadata.put("id", document.getId().toString());
            metadata.put("title", document.getTitle());
            metadata.put("knowledge_base_id", document.getKnowledgeBaseId().toString());
            metadata.put("index_name", indexName);
            
            // 添加创建者信�?
            if (document.getCreatedBy() != null) {
                metadata.put("created_by", document.getCreatedBy().toString());
            }

            // 如果有文件信息，添加到元数据
            if (document.getFileName() != null) {
                metadata.put("file_name", document.getFileName());
                metadata.put("file_path", document.getFilePath());
            }

            // 创建Spring AI文档
            // 建立阶段式文档切分结构，如果单次切分报错超过设定的token则将这一块文档再次切分后再次入库
            DocumentSplitSaveUtil documentSplitSaveUtil = new DocumentSplitSaveUtil(500, vectorStore);
            documentSplitSaveUtil.splitAndSave(document, metadata);

            System.out.println("成功将文�?ID: " + document.getId() + ")添加到向量数据库，索�? " + indexName);
        } catch (Exception e) {
            System.err.println("将文档保存到向量数据库时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

    @Override
    public List<KnowledgeDocument> getDocumentsByKnowledgeBaseId(Long knowledgeBaseId) {
        LambdaQueryWrapper<KnowledgeDocument> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(KnowledgeDocument::getKnowledgeBaseId, knowledgeBaseId);
        return documentMapper.selectList(queryWrapper);
    }

    @Override
    public KnowledgeDocument getDocumentById(Long id) {
        return documentMapper.selectById(id);
    }

    @Override
    public KnowledgeDocument updateDocument(KnowledgeDocument document) {
        // 获取现有文档
        KnowledgeDocument existingDoc = documentMapper.selectById(document.getId());
        if (existingDoc == null) {
            throw new RuntimeException("文档不存在");
        }

        // 设置更新时间
        document.setUpdateTime(LocalDateTime.now());

        // 保留不变的字�?
        document.setCreateTime(existingDoc.getCreateTime());
        document.setCreatedBy(existingDoc.getCreatedBy());

        // 如果前端没有传文件相关信息，保留原有信息
        if (document.getFileName() == null) {
            document.setFileName(existingDoc.getFileName());
        }
        if (document.getFilePath() == null) {
            document.setFilePath(existingDoc.getFilePath());
        }

        // 更新文档
        documentMapper.updateById(document);

        // 如果内容有更新且关联了知识库，更新向量数据库中的内容
    if (document.getKnowledgeBaseId() != null &&
            !document.getContent().equals(existingDoc.getContent())) {
        // 检查向量存储是否启用
        if (!vectorStoreManager.isVectorStoreEnabled()) {
            System.out.println("向量存储功能已禁用，跳过文档向量存储更新操作");
            return document;
        }
        
        // 先删除旧的向�?
        try {
            // 获取关联的知识库
            KnowledgeBase knowledgeBase = knowledgeBaseService.getKnowledgeBase(document.getKnowledgeBaseId());
            if (knowledgeBase == null) {
                System.err.println("无法更新向量数据库：找不到关联的知识库，ID: " + document.getKnowledgeBaseId());
                return document;
            }
            
            // 获取向量索引名称
            String indexName = knowledgeBase.getVectorIndexName();
            if (indexName == null || indexName.isEmpty()) {
                indexName = "kb_" + knowledgeBase.getId();
            }
            
            // 获取文档创建者的用户信息
            User user = null;
            if (document.getCreatedBy() != null) {
                user = userService.getUserById(document.getCreatedBy());
            }
            
            // 根据用户获取对应的向量存�?
            VectorStore vectorStore = aiModelInitService.getVectorStoreByUser(user, indexName);
            if (vectorStore != null) {
                // 由于Spring AI的接口限制，目前可能需要根据元数据查询和删�?
                Filter.Expression filterExpression = new Filter.Expression(
                        Filter.ExpressionType.EQ,
                        new Filter.Key("id"),
                        new Filter.Value(document.getId().toString()));
                vectorStore.delete(filterExpression);
                // 然后保存新的向量
                saveDocumentToVectorStore(document);
            }
        } catch (Exception e) {
            System.err.println("更新向量数据库时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }

        return document;
    }

    @Override
    public boolean deleteDocument(Long id) {
        // 获取文档信息，用于后续删除向量存储中的数�?
        KnowledgeDocument document = documentMapper.selectById(id);
        if (document != null && document.getKnowledgeBaseId() != null) {
            try {
                // 检查向量存储是否启用
                if (!vectorStoreManager.isVectorStoreEnabled()) {
                    System.out.println("向量存储功能已禁用，跳过文档向量存储删除操作");
                } else {
                    // 获取关联的知识库
                    KnowledgeBase knowledgeBase = knowledgeBaseService.getKnowledgeBase(document.getKnowledgeBaseId());
                    if (knowledgeBase == null) {
                        System.err.println("无法从向量数据库删除文档：找不到关联的知识库，ID: " + document.getKnowledgeBaseId());
                    } else {
                        // 获取向量索引名称
                        String indexName = knowledgeBase.getVectorIndexName();
                        if (indexName == null || indexName.isEmpty()) {
                            indexName = "kb_" + knowledgeBase.getId();
                        }
                        
                        // 获取文档创建者的用户信息
                        User user = null;
                        if (document.getCreatedBy() != null) {
                            user = userService.getUserById(document.getCreatedBy());
                        }
                        
                        // 根据用户获取对应的向量存�?
                        VectorStore vectorStore = aiModelInitService.getVectorStoreByUser(user, indexName);
                        if (vectorStore != null) {
                            // 由于Spring AI的接口限制，目前可能需要根据元数据查询和删�?
                            Filter.Expression filterExpression = new Filter.Expression(
                                    Filter.ExpressionType.EQ,
                                    new Filter.Key("id"),
                                    new Filter.Value(document.getId().toString()));
                            vectorStore.delete(filterExpression);
                        }
                    }
                }
            } catch (Exception e) {
                System.err.println("从向量数据库删除文档时出�? " + e.getMessage());
                e.printStackTrace();
            }
        }

        // 从数据库中删�?
        return documentMapper.deleteById(id) > 0;
    }

    /**
     * 文档列表
     * @param page 页码
     * @param size 每页大小
     * @param knowledgeBaseId 知识库ID（可选）
     * @return
     */
    @Override
    public Page<KnowledgeDocument> listDocuments(int page, int size, Long knowledgeBaseId) {
        Page<KnowledgeDocument> pageParam = new Page<>(page, size);
        LambdaQueryWrapper<KnowledgeDocument> queryWrapper = new LambdaQueryWrapper<>();

        // 如果指定了知识库ID，则按知识库ID过滤
        if (knowledgeBaseId != null) {
            queryWrapper.eq(KnowledgeDocument::getKnowledgeBaseId, knowledgeBaseId);
        }

        // 按创建时间降序排�?
        queryWrapper.orderByDesc(KnowledgeDocument::getCreateTime);
        
        // 排除content字段，减少数据传输量
        queryWrapper.select(KnowledgeDocument::getId, KnowledgeDocument::getTitle, 
                          KnowledgeDocument::getKnowledgeBaseId, KnowledgeDocument::getFileName,
                          KnowledgeDocument::getFilePath, KnowledgeDocument::getFileSize,
                          KnowledgeDocument::getCreatedBy, KnowledgeDocument::getCreateTime,
                          KnowledgeDocument::getUpdateTime, KnowledgeDocument::getStatus);

        return documentMapper.selectPage(pageParam, queryWrapper);
    }

    @Override
    public String addDocument(String content, Long knowledgeBaseId, String title) {
        try {
            if (content == null || content.isEmpty()) {
                return "文档内容不能为空";
            }

            // 创建新文�?
            KnowledgeDocument document = new KnowledgeDocument();
            document.setContent(content);
            document.setTitle(title);
            document.setKnowledgeBaseId(knowledgeBaseId);

            // 保存文档
            saveDocument(document);

            return "文档添加成功，ID: " + document.getId();
        } catch (Exception e) {
            return "文档添加失败: " + e.getMessage();
        }
    }

    @Override
    public KnowledgeDocument createDocumentFromFile(String fileName, String filePath, String title, Long fileSize, Long knowledgeBaseId, Long userId) {
        if (fileName == null || fileName.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        try {
            // 如果filePath是相对路径，需要转换为绝对路径
            String absoluteFilePath = filePath;
            if (!Paths.get(filePath).isAbsolute()) {
                // 使用配置的上传目�?
                absoluteFilePath = Paths.get(uploadDir, filePath).toString();
            }
            
            // 读取文件内容
            String content = readFileContent(absoluteFilePath);
            
            if (content == null || content.isEmpty()) {
                throw new IllegalArgumentException("文件内容解析为空");
            }

            // 创建文档对象
            KnowledgeDocument document = new KnowledgeDocument();
            document.setTitle(title);
            document.setContent(content);
            document.setKnowledgeBaseId(knowledgeBaseId);
            document.setCreatedBy(userId);
            document.setFileName(fileName);
            document.setFilePath(filePath); // 保存相对路径
            document.setFileSize(fileSize);

            // 保存文档
            return saveDocument(document);
        } catch (Exception e) {
            throw new RuntimeException("创建文档失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 读取文件内容
     * @param filePath 文件路径
     * @return 文件内容
     */
    private String readFileContent(String filePath) {
        try {
            Path path = Paths.get(filePath);
            if (!Files.exists(path)) {
                throw new RuntimeException("文件不存�? " + filePath);
            }
            
            // 根据文件扩展名判断文件类�?
            String fileName = path.getFileName().toString().toLowerCase();
            if (fileName.endsWith(".pdf")) {
                return readPdfContent(path);
            } else if (fileName.endsWith(".docx")) {
                return readDocxContent(path);
            } else if (fileName.endsWith(".txt") || fileName.endsWith(".md")) {
                return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
            } else {
                // 尝试作为文本文件读取
                return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            throw new RuntimeException("读取文件内容失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 读取PDF文件内容
     * @param path PDF文件路径
     * @return PDF文件内容
     */
    private String readPdfContent(Path path) {
        try {
            // 这里应该使用PDF解析库，如Apache PDFBox
            // 为了简化，这里只是示例，实际项目中需要添加PDFBox依赖
            // PDFBoxPDDocument document = new PDFBoxPDDocument();
            // document.load(path.toFile());
            // String text = new PDFTextStripper().getText(document);
            // document.close();
            // return text;
            
            // 临时实现：读取为文本
            return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new RuntimeException("读取PDF文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 读取DOCX文件内容
     * @param path DOCX文件路径
     * @return DOCX文件内容
     */
    private String readDocxContent(Path path) {
        try {
            // 这里应该使用DOCX解析库，如Apache POI
            // 为了简化，这里只是示例，实际项目中需要添加POI依赖
            // XWPFDocument document = new XWPFDocument(Files.newInputStream(path));
            // XWPFWordExtractor extractor = new XWPFWordExtractor(document);
            // String text = extractor.getText();
            // extractor.close();
            // document.close();
            // return text;
            
            // 临时实现：读取为文本
            return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new RuntimeException("读取DOCX文件失败: " + e.getMessage(), e);
        }
    }
}
